﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using MacomberMapSystem.Common.Database;
using System.Threading;
using MacomberMapSystem.Common.CIM;
using System.Data.Common;
using System.Xml;
using MacomberMapSystem.Common.Internals;
using System.IO;

namespace MacomberMapSystem.Common.User_Interfaces.One_Lines
{
    /// <summary>
    /// This form allows exploration of alternate possibilities for a one-line assignment
    /// </summary>
    public partial class frmAlternateOneLineEvaluator : Form
    {
        #region Variable declarations
        /// <summary>Our assignment</summary>
        private MM_Database_Assignment Assignment;
        #endregion


        /// <summary>
        /// Initialize a new alternate one-line evaluator
        /// </summary>
        public frmAlternateOneLineEvaluator(MM_Database_Assignment Assignment)
        {
            InitializeComponent();
            this.Text = "Alternative one-line evaluator: " + Assignment.OneLineType.ToString() + " " + Assignment.OneLineName;
            this.Assignment = Assignment;
        }

        /// <summary>
        /// When the form is shown, kick off a thread to validate everything
        /// </summary>
        /// <param name="e"></param>
        protected override void OnShown(EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;

            //First, make sure the model is opened.
            if (Assignment.Model.State == MM_Database_Model.enumModelState.Unopened)
                if (MessageBox.Show("Open model " + Assignment.Model.Name + "?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                {
                    this.Close();
                    return;
                }
                else
                    Assignment.Model.InitiateLoading();

            while (Assignment.Model.State != MM_Database_Model.enumModelState.Completed)
            {
                Thread.Sleep(500);
                Application.DoEvents();
            }

            ThreadPool.QueueUserWorkItem(new WaitCallback(Validate));
            base.OnShown(e);
        }



        /// <summary>
        /// Perform the actual validations
        /// </summary>
        /// <param name="state"></param>
        private void Validate(object state)
        {
            CIM_Element Sub;
            if (!Assignment.Model.Substations.TryGetValue(Assignment.OneLineName, out Sub))
                return;

            //Pull all one-lines for the current substation            
            List<MM_OneLineValidation> Validations = new List<MM_OneLineValidation>();
            using (DbCommand dCmd = Assignment.Model.Repository.Db.CreateCommand("SELECT Document, ID, LastExported FROM MM_DATABASE_ONELINE WHERE rdfID=:0", Sub.rdfID.ToString()))
            using (DbDataReader dRd = dCmd.ExecuteReader())
                while (dRd.Read())
                    Validations.Add(new MM_OneLineValidation(dRd, Sub, Assignment.Model.Repository));
            Validations.Sort();            
            ApplyValidations(Validations);
        }

        private delegate void SafeApplyValidations(List<MM_OneLineValidation> Validations);
        /// <summary>
        /// Write out the validation collection
        /// </summary>
        /// <param name="Validations"></param>
        private void ApplyValidations(List<MM_OneLineValidation> Validations)
        {
            if (lvValidations.InvokeRequired)
                lvValidations.Invoke(new SafeApplyValidations(ApplyValidations), Validations);
            else
            {
                lvValidations.Items.Clear();
                foreach (MM_OneLineValidation Val in Validations)
                {
                    ListViewItem lvI = lvValidations.Items.Add(Val.ID.ToString("#,##0"));
                    lvI.Tag = Val;
                    if (Val.LastExported == DateTime.MinValue)
                        lvI.SubItems.Add("");
                    else
                        lvI.SubItems.Add(Val.LastExported.ToShortDateString());
                    lvI.SubItems.Add(Val.Errors.ToString("#,##0"));
                    lvI.SubItems.Add(Val.Warnings.ToString("#,##0"));
                }
                MessageBox.Show("Validations completed.");
                this.Cursor = Cursors.Default;
            }
           
        }

        /// <summary>
        /// Reassign to this one-line, and click ok.        
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnReassign_Click(object sender, EventArgs e)
        {
            MM_OneLineValidation SelVal;
            if (lvValidations.SelectedItems.Count != 1)
                return;
            else if ((SelVal = lvValidations.SelectedItems[0].Tag as MM_OneLineValidation) == null)
                return;
            if (MessageBox.Show("Are you sure you would like to reassign one-line " + Assignment.OneLineName + " to ID#" + SelVal.ID.ToString("#,##0") + "?", Application.ProductName, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                //Write the one-line XML into the one-line.
                using (DbCommand dCmd = Assignment.Model.Repository.Db.CreateCommand("UPDATE MM_DATABASE_ONELINE SET DOCUMENT=:0 WHERE ID=:1", SelVal.xDoc.OuterXml, SelVal.ID))
                    if (dCmd.ExecuteNonQuery() != 1)
                        throw new InvalidOperationException("Expecting one one-line to be updated for an alternate one-line");
                Assignment.OneLine = SelVal.ID;

                this.DialogResult = DialogResult.OK;
                this.Close();                
            }

        }

        /// <summary>
        /// Handle the user's changing the index
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lvValidations_SelectedIndexChanged(object sender, EventArgs e)
        {
            lbResults.Items.Clear();
                
            if (lvValidations.SelectedItems.Count != 1)            
                olPreview.AssignOneLine(null, null, null, Assignment.Model.Repository);            
            else
            {
                MM_OneLineValidation SelVal = lvValidations.SelectedItems[0].Tag as MM_OneLineValidation;
                Assignment.Model.Repository.Db.LoadOneLine(SelVal.ID, Assignment.Model.Repository);
                olPreview.AssignOneLine(Assignment.Model.Repository.Db.LoadOneLine(SelVal.ID, Assignment.Model.Repository), Assignment.Model.Repository.Db.LoadOneLineImage(SelVal.ID), Assignment.Model, Assignment.Model.Repository);
                String InLine;
                using (StringReader sRd = new StringReader(SelVal.ValidationText))
                    while ((InLine = sRd.ReadLine()) != null)
                        lbResults.Items.Add(InLine);
            }
        }
    }
}
